package com.hulk.dryad.activiti7.service.impl;



import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hulk.dryad.manage.boot.upload2.DryadUploadProperties;
import com.hulk.dryad.persistence.entity.DefinitionId;
import com.hulk.dryad.persistence.entity.ProcessDefinitionModel;
import com.hulk.dryad.persistence.entity.ActReDeployment;
import com.hulk.dryad.persistence.mapper.ActReDeploymentMapper;
import com.hulk.dryad.activiti7.service.IProcessDefinitionService;
import lombok.AllArgsConstructor;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntityImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.apache.commons.io.FilenameUtils;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.web.multipart.MultipartFile;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.file.Files;

import java.nio.file.Paths;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.zip.ZipInputStream;

/**
 *
 * 创建日期:2020/10/23-9:52
 * 版本   开发者     日期
 * 1.0.0   hulk     2020/10/23
 */

@Service
@AllArgsConstructor
public class ProcessDefinitionServiceImpl implements IProcessDefinitionService {


	private  static final String ZIP = "zip";

    private RepositoryService repositoryService;

    private ActReDeploymentMapper actReDeploymentMapper;

    private HistoryService historyService;

    private RuntimeService runtimeService;

	private  DryadUploadProperties dryadUploadProperties;

    @Override
    public Page<ProcessDefinitionModel> getProcessDefinitionPage(Page page, ProcessDefinitionModel processDefinitionModel) {

        ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery().orderByProcessDefinitionId().orderByProcessDefinitionVersion().desc();
        if (StrUtil.isNotBlank(processDefinitionModel.getName())) {
            processDefinitionQuery.processDefinitionNameLike("%" + processDefinitionModel.getName() + "%");
        }
        if (StrUtil.isNotBlank(processDefinitionModel.getKey())) {
            processDefinitionQuery.processDefinitionKeyLike("%" + processDefinitionModel.getKey() + "%");
        }
        List<ProcessDefinition> processDefinitions = processDefinitionQuery.listPage((int)((page.getCurrent() - 1) * page.getSize()), (int)page.getSize());
        long count = processDefinitionQuery.count();
       	page.setTotal(count);
        if (!CollectionUtils.isEmpty(processDefinitions)) {
            Set<String> deploymentIds = processDefinitions.parallelStream().map(pdl -> pdl.getDeploymentId()).collect(Collectors.toSet());
            List<ActReDeployment> actReDeployments = actReDeploymentMapper.selectActReDeploymentByIds(deploymentIds);
            List<ProcessDefinitionModel> processDefinitionModels = processDefinitions.stream()
                    .map(pd -> new ProcessDefinitionModel((ProcessDefinitionEntityImpl) pd, actReDeployments.parallelStream().filter(ard -> pd.getDeploymentId().equals(ard.getId())).findAny().orElse(new ActReDeployment())))
                    .collect(Collectors.toList());
            page.setRecords(processDefinitionModels);
        }
        return page;
    }

    @Override
    public DefinitionId getDefinitionByInstanceId(String instanceId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(instanceId).singleResult();
        String deploymentId = processInstance.getDeploymentId();
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
        return new DefinitionId(processDefinition);
    }

    @Override
    public void removeProcessDefinitionById(String id) {
       repositoryService.deleteDeployment(id, false);
    }

    @Override
    public void suspendOrActiveApply(String id, Integer suspendState) {
        if (1==suspendState) {
            // 当流程定义被挂起时，已经发起的该流程定义的流程实例不受影响（如果选择级联挂起则流程实例也会被挂起）。
            // 当流程定义被挂起时，无法发起新的该流程定义的流程实例。
            // 直观变化：act_re_procdef 的 SUSPENSION_STATE_ 为 2
            repositoryService.suspendProcessDefinitionById(id);
        } else if (2==suspendState) {
            repositoryService.activateProcessDefinitionById(id);
        }
    }

	@Override
	public void uploadStreamAndDeployment(MultipartFile file,String deploymentName) throws IOException {
		// 获取上传的文件名
		String fileName = file.getOriginalFilename();
		// 得到输入流（字节流）对象
		InputStream fileInputStream = file.getInputStream();
		// 文件的扩展名
		String extension = FilenameUtils.getExtension(fileName);

		if(ZIP.equalsIgnoreCase(extension)) {
			ZipInputStream zip = new ZipInputStream(fileInputStream);
			repositoryService.createDeployment()//初始化流程
					.addZipInputStream(zip).name(deploymentName)
					.deploy();
		} else {
			repositoryService.createDeployment()//初始化流程
					.addInputStream(fileName, fileInputStream).name(deploymentName)
					.deploy();
		}
	}

    @Override
    public String upload(MultipartFile multipartFile)  {
		// 文件信息
		String fileName = multipartFile.getOriginalFilename();
		String fileExtension = FileNameUtil.extName(fileName);
		// 文件保存路径
		String filePath = IdUtil.simpleUUID() + StrUtil.DOT+ fileExtension;
		File uploadFile = Paths.get(dryadUploadProperties.getSavePath(),"processDefinition",filePath).toFile();
		try {
			if (uploadFile.exists()) {
				Files.delete(uploadFile.toPath());
			}
			File uploadDir = uploadFile.getParentFile();
			if (!uploadDir.exists()) {
				uploadDir.mkdirs();
			}
			multipartFile.transferTo(uploadFile);
		} catch (Throwable e) {
			throw new RuntimeException("文件上传异常", e);
		}
       return uploadFile.getAbsolutePath();
    }

    @Override
    public void addDeploymentByString(String stringBPMN,String deploymentName) {
        repositoryService.createDeployment()
                .addString("CreateWithBPMNJS.bpmn", stringBPMN).name(deploymentName)
                .deploy();
    }

    @Override
    public void getProcessDefineXML(HttpServletResponse response, String deploymentId, String resourceName) throws IOException {
        InputStream inputStream = repositoryService.getResourceAsStream(deploymentId, resourceName);
        int count = inputStream.available();
        byte[] bytes = new byte[count];
        response.setContentType(MediaType.TEXT_XML_VALUE);
        OutputStream outputStream = response.getOutputStream();
        while (inputStream.read(bytes) != -1) {
            outputStream.write(bytes);
        }
        inputStream.close();
    }
}
